﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using JESAI.Core.Extensions;

namespace JESAI.Core.Data.Pages
{
    /// <summary>
    /// 通用结果模型
    /// </summary>
    [JsonObject(MemberSerialization.OptOut)]
    [DataContract]
    public class Result<T>
    {
        /// <summary>
        /// 可以使用 <seealso cref="Result.NewInstance{T}"/> 代替!
        /// </summary>
        public Result() { }

        /// <summary>
        /// 状态码,一般用来表示错误类别
        /// </summary>
        [DataMember(Order = 1)]
        public int Code { get; set; }

        /// <summary>
        /// 消息文本,一般用来做错误提示
        /// </summary>
        [DataMember(Order = 2)]
        public string Message { get; set; }

        /// <summary>
        /// 详细消息文本,可用来做详细的错误提示
        /// </summary>
        [DataMember(Order = 3)]
        public object ExtData { get; set; }

        /// <summary>
        /// 执行成功或失败
        /// </summary>
        [DataMember(Order = 4)]
        public bool Success { get; set; }

        /// <summary>
        /// 执行的结果数据
        /// </summary>
        [DataMember(Order = 5)]
        public T Data { get; set; }

        /// <summary>
        /// 隐示转换
        /// </summary>
        /// <param name="res"></param>
        public static implicit operator Result<T>(Result res)
        {
            if (res.Data is T t)
            {
                return new Result<T>()
                {
                    Code = res.Code,
                    Message = res.Message,
                    ExtData = res.ExtData,
                    Success = res.Success,
                    Data = t
                };
            }
            else
            {
                T tmp = default(T);
                if (typeof(T).IsSimpleType())
                {
                    try
                    {
                        tmp = res.Data.To<T>();
                    }
                    catch { }
                }
                else
                {
                    try
                    {
                        tmp = (T)res.Data.Mapper(typeof(T));
                    }
                    catch { }
                }
                return new Result<T>()
                {
                    Code = res.Code,
                    Message = res.Message,
                    ExtData = res.ExtData,
                    Success = res.Success,
                    Data = tmp
                };
            }

        }

        #region 设置数据
        /// <summary>
        /// 设置数据
        /// </summary>
        /// <param name="data">数据模型</param>
        /// <returns></returns>
        public Result<T> SetData(T data)
        {
            this.Data = data;
            return this;
        }

        /// <summary>
        /// 设置数据
        /// </summary>
        /// <param name="data">数据模型</param>
        /// <returns></returns>
        public Result<T> SetData(object data)
        {
            if (data is T t) this.Data = t;
            else
            {
                if (data == null) this.Data = default(T);
                else
                {
                    this.Data = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(data));
                }
            }
            return this;
        }

        /// <summary>
        /// 设置Code
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public Result<T> SetCode(int code)
        {
            this.Code = code;
            return this;
        }

        /// <summary>
        /// 设置响应消息
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public Result<T> SetMessage(string message)
        {
            this.Message = message;
            return this;
        }

        /// <summary>
        /// 将响应标记成功
        /// </summary>
        /// <returns></returns>
        public Result<T> SetSuccess()
        {
            this.Success = true;
            return this;
        }

        /// <summary>
        /// 将响应标记失败
        /// </summary>
        /// <returns></returns>
        public Result<T> SetFail()
        {
            this.Success = false;
            return this;
        }

        /// <summary>
        /// 设置响应标记
        /// </summary>
        /// <returns></returns>
        public Result<T> SetSuccessFlag(bool isSuccess)
        {
            this.Success = isSuccess;
            return this;
        }

        /// <summary>
        /// 设置扩展数据
        /// </summary>
        /// <param name="extData">扩展数据</param>
        /// <returns></returns>
        public Result<T> SetExtData(object extData)
        {
            this.ExtData = extData;
            return this;
        }
        #endregion
    }

    /// <summary>
    /// 以object作为结果数据类别,提供静态快捷方法
    /// </summary>
    [DataContract]
    public class Result : Result<object>
    {
        /// <summary>
        /// 可以使用 <seealso cref="Result.NewInstance"/> 代替!
        /// </summary>
        public Result() { }

        #region 设置数据
        /// <summary>
        /// 设置数据
        /// </summary>
        /// <param name="data">数据模型</param>
        /// <returns></returns>
        public new Result SetData(object data)
        {
            this.Data = data;
            return this;
        }

        /// <summary>
        /// 设置Code
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public new Result SetCode(int code)
        {
            this.Code = code;
            return this;
        }

        /// <summary>
        /// 设置响应消息
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public new Result SetMessage(string message)
        {
            this.Message = message;
            return this;
        }

        /// <summary>
        /// 将响应标记成功
        /// </summary>
        /// <returns></returns>
        public new Result SetSuccess()
        {
            this.Success = true;
            return this;
        }

        /// <summary>
        /// 将响应标记失败
        /// </summary>
        /// <returns></returns>
        public new Result SetFail()
        {
            this.Success = false;
            return this;
        }

        /// <summary>
        /// 设置响应标记
        /// </summary>
        /// <returns></returns>
        public new Result SetSuccessFlag(bool isSuccess)
        {
            this.Success = isSuccess;
            return this;
        }

        /// <summary>
        /// 设置扩展数据
        /// </summary>
        /// <param name="extData">扩展数据</param>
        /// <returns></returns>
        public new Result SetExtData(object extData)
        {
            this.ExtData = extData;
            return this;
        }
        #endregion

        #region NewInstance
        /// <summary>
        /// 创建Result实例
        /// </summary>
        /// <returns></returns>
        public static Result NewInstance() => new Result();

        /// <summary>
        /// 创建Result&lt;T>实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Result<T> NewInstance<T>() => new Result<T>();
        #endregion

        /// <summary>
        /// 返回成功,使用json序列化机制转换到目标类型
        /// </summary>
        /// <param name="value">模型数据</param>
        /// <returns></returns>
        public static Result<T> Ok<T>(object value)
        {
            if (value is T t) return new Result<T>()
            {
                Success = true,
                Data = t
            };
            var json = Newtonsoft.Json.JsonConvert.SerializeObject(value);
            t = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(json);
            return new Result<T>()
            {
                Success = true,
                Data = t
            };
        }

        /// <summary>
        /// 返回成功
        /// </summary>
        /// <param name="value">模型数据</param>
        /// <returns></returns>
        public static Result<T> Ok<T>(T value)
        {
            return new Result<T>()
            {
                Success = true,
                Data = value
            };
        }

        /// <summary>
        /// 返回成功,不需要附带模型数据
        /// </summary>
        /// <returns></returns>
        public static Result Ok()
        {
            return new Result()
            {
                Success = true
            };
        }

        /// <summary>
        /// 返回分页模型数据
        /// </summary>
        /// <param name="totalCount">数据总量</param>
        /// <param name="list">当前页码内的数据</param>
        /// <returns></returns>
        public static ResultPage<T> OkPage<T>(long totalCount, IEnumerable<T> list)
        {
            return new ResultPage<T>()
            {
                Success = true,
                Data = new Page<T>()
                {
                    TotalCount = totalCount,
                    List = list
                }
            };
        }

        /// <summary>
        /// 返回分页模型数据
        /// </summary>
        /// <param name="totalCount">数据总量</param>
        /// <param name="list">当前页码内数量</param>
        /// <returns></returns>
        public static ResultPage<T> OkPage<T>(long totalCount, object[] list) where T : class, new()
        {
            if (typeof(T) == typeof(object))
            {
                return new ResultPage<T>()
                {
                    Success = true,
                    Data = new Page<T>()
                    {
                        TotalCount = totalCount,
                        List = (T[])list
                    }
                };
            }
            return new ResultPage<T>()
            {
                Success = true,
                Data = new Page<T>()
                {
                    TotalCount = totalCount,
                    List = list.Mapper<List<T>>()
                }
            };
        }

        /// <summary>
        /// 返回失败结果
        /// </summary>
        /// <param name="message">失败提示</param>
        /// <param name="code">错误码</param>
        /// <param name="data">模型数据</param>
        /// <param name="extData">扩展数据</param>
        /// <returns></returns>
        public static Result NotOk(string message, int code = 0, object data = null, object extData = null)
        {
            return new Result()
            {
                Success = false,
                Message = message,
                ExtData = extData,
                Code = code,
                Data = data
            };
        }

        /// <summary>
        /// 返回异步结果
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="task"></param>
        /// <returns></returns>
        public static async Task<Result<T>> OkAsync<T>(Task<T> task)
        {
            var res = await task;
            return Result.Ok(res);
        }

        /// <summary>
        /// 当data不为null时返回true，否则返回false
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <returns></returns>
        public static Result<T> OkIfNotNull<T>(T data)
        {
            if (data == null) return Result.NotOk("无数据!");
            return Result.Ok(data);
        }

        /// <summary>
        /// 返回异步结果
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="task"></param>
        /// <returns></returns>
        public static async Task<Result<T>> OkIfNotNullAsync<T>(Task<T> task)
        {
            var res = await task;
            if (res == null) return Result.NotOk("无数据!");
            return Result.Ok(res);
        }

        /// <summary>
        /// 包裹程序段,捕捉程序段内的异常并使用Result模型封装
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func">委托</param>
        /// <returns></returns>
        /// <remarks>注意：如果func为null，则则认为执行成功并返回模型的默认值</remarks>
        public static Result<T> WrapReturn<T>(Func<T> func)
        {
            if (func == null) return Result.Ok(default(T));
            try
            {
                var t = func();
                return Result.Ok(t);
            }
            catch (Exception ex)
            {
                return Result.NotOk(ex?.Message);
            }
        }

        /// <summary>
        /// 包裹异步程序段,捕捉程序段内的异常并使用Result模型封装
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func">委托</param>
        /// <returns></returns>
        /// <remarks>注意：如果func为null，则则认为执行成功并返回模型的默认值</remarks>
        public static async Task<Result<T>> WrapReturn<T>(Func<Task<T>> func)
        {
            if (func == null) return Result.Ok(default(T));
            try
            {
                var t = await func();
                return Result.Ok(t);
            }
            catch (Exception ex)
            {
                return Result.NotOk(ex?.Message);
            }
        }

        /// <summary>
        /// 包裹程序段,捕捉程序段内的异常并使用Result模型封装
        /// </summary>
        /// <param name="action">委托</param>
        /// <returns></returns>
        /// <remarks>注意：如果action为null，则认为执行成功</remarks>
        public static Result Wrap(Action action)
        {
            if (action == null) return Result.Ok();
            try
            {
                action();
                return Result.Ok();
            }
            catch (Exception ex)
            {
                return Result.NotOk(ex?.Message);
            }
        }

        /// <summary>
        /// 包裹异步程序段,捕捉程序段内的异常并使用Result模型封装
        /// </summary>
        /// <param name="action">委托</param>
        /// <returns></returns>
        /// <remarks>注意：如果action为null，则认为执行成功</remarks>
        public static async Task<Result> Wrap(Func<Task> action)
        {
            if (action == null) return Result.Ok();
            try
            {
                await action();
                return Result.Ok();
            }
            catch (Exception ex)
            {
                return Result.NotOk(ex?.Message);
            }
        }
    }

    /// <summary>
    /// Result扩展类
    /// </summary>
    public static class ResultExtensions
    {
        /// <summary>
        /// 解开Result模型,null值则返回 default(T)
        /// Result.Success为true则返回模型,否则抛出ResultException异常
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="result"></param>
        /// <returns></returns>
        public static T UnWrap<T>(this Result<T> result)
        {
            if (result.Success) return result.Data;
            throw new Exception(result.Message);
        }
    }
}
